import sys, os
import threading
import h5py

from PySide6.QtCore import Qt
from PySide6.QtGui import QBrush, QMouseEvent, QPainter, QPaintEvent, QColor
from PySide6.QtWidgets import QApplication, QWidget

from ..dlgo.agent import RandmomAgent, DeepLearningAgent, LoadPredictionAgent
from ..dlgo.board import GameState, Board as DlgoBoard, Point, Move
from ..dlgo.utils import Player
from ..utils import R

RootDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
BotPath = os.path.join(os.path.dirname(RootDir), 'deep_bot.h5')

class Board(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        w = (R.BoardSize+1) * R.StoneSize
        self.resize(w, w)
        self.setStyleSheet("background-color: rgb(230, 230, 80);")
        
        self.board:DlgoBoard = None
        self.next_point:Point = None
        self.game = GameState.NewGame(R.BoardSize)
        self.board_width = (R.BoardSize - 1) * R.StoneSize
        self.use_press = True

    def UpdateLeftTop(self):
        self.x0, self.y0 = (
            (self.width() - self.board_width) / 2,
            (self.height() - self.board_width) / 2,
        )

    def paintEvent(self, e: QPaintEvent) -> None:
        self.UpdateLeftTop()
        self.DrawBoard()
        self.DrawStones()

    def mousePressEvent(self, e: QMouseEvent) -> None:
        if not self.use_press: return
        x, y = (
            e.x() - self.x0 + R.StoneSize / 2 - 1,
            e.y() - self.y0 + R.StoneSize / 2 - 1,
        )
        col = int(x / R.StoneSize)
        row = int(y / R.StoneSize)
        if self.ValidMove(col,row):
            if e.button() == Qt.LeftButton:
                self.next_point = Point(row+1, col+1)
                self.NextMove()
                self.update()
                self.next_point = None

    def ValidMove(self, col, row):
        return 0 <= col < R.BoardSize and 0 <= row < R.BoardSize
    
    def DrawBoard(self):
        x0, y0 = self.x0, self.y0
        baord_width = self.board_width
        
        # fmt: off
        stars = [
            (3, 3), (9, 3), (15, 3),
            (3, 9), (9, 9), (15, 9),
            (3, 15), (9, 15), (15, 15),
        ]
        # fmt: on

        painter = QPainter()
        painter.begin(self)
        for x in range(R.BoardSize):
            for y in range(R.BoardSize):
                painter.drawLine(
                    x0, y0 + y * R.StoneSize, x0 + baord_width, y0 + y * R.StoneSize
                )
                painter.drawLine(
                    x0 + x * R.StoneSize, y0, x0 + x * R.StoneSize, y0 + baord_width
                )
                if R.BoardSize != 19: continue
                if (x, y) in stars:
                    painter.setBrush(Qt.black)
                    painter.drawEllipse(
                        x0 + x * R.StoneSize - R.StoneSize / 6,
                        y0 + y * R.StoneSize - R.StoneSize / 9,
                        R.StoneSize / 3,
                        R.StoneSize / 3,
                    )
        painter.end()

    def DrawStones(self):
        if self.board is None: return
        board = self.board
        painter = QPainter()
        painter.begin(self)
        for r in range(board.rows):
            for c in range(board.cols):
                player:Player = board.GetPlayer(Point(r+1,c+1))
                if player is None: continue
                b = QBrush(Qt.black) if player == Player.black else QBrush(QColor('#adafaf'))
                painter.setBrush(b)
                painter.drawEllipse(
                    self.x0 + c * R.StoneSize - R.StoneSize / 2,
                    self.y0 + r * R.StoneSize - R.StoneSize / 2,
                    R.StoneSize,
                    R.StoneSize,
                )
        painter.end()

    def NextMove(self):
        if self.next_point is None: return
        
        if not self.game.IsOver():
            move = Move.Play(self.next_point)
            self.game = self.game.ApplyMove(move)
            self.board = self.game.board


class AiBoard(Board):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        
        self.use_press = False
        self._thread = threading.Thread(target=self.Start, daemon=True)
        self._thread.start()
        
    def Start(self):
        for move in self.GetMoves():
            self.update()

    def GetMoves(self):
        import time
        game = self.game
        deep_bot = LoadPredictionAgent(h5py.File(BotPath, 'r'))
        agents = {Player.black: deep_bot, Player.white: RandmomAgent()}
        while not game.IsOver():
            # time.sleep(0.1)
            move = agents[game.next_player].SelectMove(game)
            game = game.ApplyMove(move)
            self.board = game.board
            yield move
        print("Game Over!\n")
        self._thread.join()

def run():
    app = QApplication(sys.argv)
    board = Board()
    board.show()
    sys.exit(app.exec_())
